package com.ybbase.framework.controller.flow.base;

import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.ybbase.framework.base.controller.BaseController;
import com.ybbase.framework.base.model.ResponseBean;
import com.ybbase.framework.common.constant.CommonResultCode;
import com.ybbase.framework.model.enumeration.FlowApproveOpinion;
import com.ybbase.framework.model.po.flow.AuditInfo;
import com.ybbase.framework.model.po.flow.InstanceRecord;
import com.ybbase.framework.model.po.flow.NodeConfig;
import com.ybbase.framework.model.po.flow.NodeRecord;
import com.ybbase.framework.model.vo.BusinessEntityVO;
import com.ybbase.framework.service.flow.*;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiImplicitParam;
import io.swagger.annotations.ApiImplicitParams;
import io.swagger.annotations.ApiOperation;
import org.activiti.engine.HistoryService;
import org.activiti.engine.RepositoryService;
import org.activiti.engine.RuntimeService;
import org.activiti.engine.TaskService;
import org.activiti.engine.history.HistoricTaskInstance;
import org.activiti.engine.impl.persistence.entity.ProcessDefinitionEntity;
import org.activiti.engine.impl.pvm.process.ActivityImpl;
import org.activiti.engine.repository.ProcessDefinition;
import org.activiti.engine.runtime.ProcessInstance;
import org.activiti.engine.task.Task;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.*;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

/**
 * @author cg
 * @date 2019-09-02 09:23
 * @DEC 基础节点操作类
 */
@RestController
@RequestMapping("/base_flow")
@Api(value = "基础节点操作类", tags = "基础节点操作类")
public class BaseFlowController extends BaseController {

    private static final Logger LOGGER = LoggerFactory.getLogger(BaseFlowController.class);

    @Autowired
    BaseFlowService baseFlowService;
    @Autowired
    ProcessCoreService processCoreService;
    @Autowired
    InstanceRecordService instanceRecordService;
    @Autowired
    RuntimeService runtimeService;
    @Autowired
    TaskService taskService;
    @Autowired
    RepositoryService repositoryService;
    @Autowired
    public NodeConfigService nodeConfigService;
    @Autowired
    public NodeRecordService nodeRecordService;
    @Autowired
    HistoryService historyService;
    /**
     * 流程提交方法
     *
     * @param businessId 业务ID也就是合同的编码
     * @return
     * @throws
     * @author cg
     * @date 2019-09-06 15:09
     * @since
     */
    @PutMapping("/commitTask")
    @ApiOperation(value = "流程提交方法", notes = "流程提交方法")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "businessId", value = "业务ID（所属业务的ID例如合同的ID）", required = true, dataType = "String"),
            @ApiImplicitParam(name = "flowCode", value = "流程编码", required = true, dataType = "String")
    })
    public ResponseBean commitTask(String businessId, String flowCode, HttpServletRequest request) {
        String userId = this.getUserId(this.getTokenString(request));
        Map<String, Object> variables = new HashMap<>();
        // 封装业务VO
        BusinessEntityVO businessEntityVO = new BusinessEntityVO();
        businessEntityVO.setBusinessId(businessId);
        businessEntityVO.setFlowCode(flowCode);
        // 封装实例记录
        List<Task> taskss = new ArrayList<>();
        try {
            InstanceRecord instanceRecord = instanceRecordService.getInstanceRecordByObj(businessId,flowCode);
            if (instanceRecord != null) {
                List<Task> tasks = baseFlowService.getInstanceUserTasks(instanceRecord.getRunProcessInstanceId(), userId);
                if (tasks.size() > 0) {
                    processCoreService.commitProcess(tasks.get(0).getId(), variables, null, businessEntityVO);
                }
                taskss =taskService.createTaskQuery().active().processInstanceId(instanceRecord.getRunProcessInstanceId()).list();
            }
            return new ResponseBean(CommonResultCode.SUCCESS.getCode(), "提交" + CommonResultCode.SUCCESS.getMsg(), taskss);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("流程提交方法：" + e.getMessage());
            return new ResponseBean(CommonResultCode.FAIL.getCode(), "提交" + CommonResultCode.FAIL.getMsg() + "，请联系管理员！", null);
        }
    }

    /**
     * 根据审核的意见和审核的结果进行提交任务信息，并保存信息
     *
     * @param auditInfo 审核信息
     * @return
     * @throws
     * @author cg
     * @date 2019-09-05 20:52
     * @since
     */
    @PutMapping("/saveTaskInfo")
    @ApiOperation(value = "根据审核的意见和审核的结果进行提交任务信息，并保存信息", notes = "根据审核的意见和审核的结果进行提交任务信息，并保存信息")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "auditInfo", value = "审核信息实体", required = true, dataType = "AuditInfo"),
            @ApiImplicitParam(name = "businessId", value = "业务ID（所属业务的ID例如合同的ID）", required = true, dataType = "String"),
            @ApiImplicitParam(name = "flowCode", value = "流程编码", required = true, dataType = "String")
    })
    public ResponseBean saveTaskInfo(AuditInfo auditInfo, String businessId, String flowCode, HttpServletRequest request) {
        String userId = this.getUserId(this.getTokenString(request));
        Map<String, Object> variables = new HashMap<>();
        // 封装业务VO
        BusinessEntityVO businessEntityVO = new BusinessEntityVO();
        businessEntityVO.setBusinessId(businessId);
        businessEntityVO.setFlowCode(flowCode);
        // 封装实例记录
        InstanceRecord instanceRecord = instanceRecordService.getInstanceRecordByObj(businessId,flowCode);
        List<Task> taskss = new ArrayList<>();
        try {
            if (instanceRecord != null) {
                List<Task> tasks = baseFlowService.getInstanceUserTasks(instanceRecord.getRunProcessInstanceId(), userId);
                if (tasks.size() > 0) {
                    QueryWrapper<NodeConfig> configQueryWrapper = new QueryWrapper<>();
                    configQueryWrapper.lambda().eq(NodeConfig::getFlowCode, flowCode);
                    configQueryWrapper.lambda().eq(NodeConfig::getNodeCode, tasks.get(0).getTaskDefinitionKey());
                    List<NodeConfig> list = nodeConfigService.list(configQueryWrapper);
                    if (list != null && list.size() > 0) {
                        //String auditStr
                        variables.put(list.get(0).getOrderCode(), auditInfo.getAudit());
                        variables.put(FlowApproveOpinion.APPROVE_MESSAGE.getValue(), auditInfo.getInstructions());
                        processCoreService.commitProcess(tasks.get(0).getId(), variables, null, businessEntityVO);
                    }
                }
                taskss =taskService.createTaskQuery().active().processInstanceId(instanceRecord.getRunProcessInstanceId()).list();
            }
            if (auditInfo.getAudit() == 1) {
                return new ResponseBean(CommonResultCode.SUCCESS.getCode(), "审核同意" + CommonResultCode.SUCCESS.getMsg(), taskss);
            } else {
                return new ResponseBean(CommonResultCode.SUCCESS.getCode(), "审核退回" + CommonResultCode.SUCCESS.getMsg(), taskss);
            }
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("根据审核的意见和审核的结果进行提交任务信息：" + e.getMessage());
            return new ResponseBean(CommonResultCode.FAIL.getCode(), "审核" + CommonResultCode.FAIL.getMsg() + "，请联系管理员！", null);
        }
    }

    /**
     * 流程撤回方法
     *
     * @param businessId 业务编码
     * @return
     * @throws
     * @author cg
     * @date 2019-09-06 15:09
     * @since
     */
    @PutMapping("/callback")
    @ApiOperation(value = "流程撤回方法", notes = "流程撤回方法")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "businessId", value = "业务ID（所属业务的ID例如合同的ID）", required = true, dataType = "String"),
            @ApiImplicitParam(name = "flowCode", value = "流程编码", required = true, dataType = "String")
    })
    public ResponseBean callBackProcess(String businessId, String flowCode, HttpServletRequest request) {
        String userId = this.getUserId(this.getTokenString(request));
        BusinessEntityVO businessEntityVO = new BusinessEntityVO();
        businessEntityVO.setBusinessId(businessId);
        businessEntityVO.setFlowCode(flowCode);
        Map<String, Object> variables = new HashMap<>();
        // 封装实例记录
        InstanceRecord instanceRecord = instanceRecordService.getInstanceRecordByObj(businessId, flowCode);
        try {
            if (instanceRecord != null) {
                // 根据流程实例id获取流程实例
                List<HistoricTaskInstance> ts = historyService.createHistoricTaskInstanceQuery().processInstanceId(instanceRecord.getRunProcessInstanceId()).processUnfinished().orderByTaskCreateTime().desc().list();
                if (ts!=null&&ts.size()>1) {
                    QueryWrapper<NodeConfig> configQueryWrapper = new QueryWrapper<>();
                    configQueryWrapper.lambda().eq(NodeConfig::getFlowCode, flowCode);
                    configQueryWrapper.lambda().eq(NodeConfig::getNodeCode, ts.get(0).getTaskDefinitionKey());
                    List<NodeConfig> list = nodeConfigService.list(configQueryWrapper);
                    if (list != null && list.size() > 0) {
                        //String auditStr
                        variables.put(list.get(0).getFlowCode(), -1);
                        variables.put(FlowApproveOpinion.APPROVE_MESSAGE.getValue(), "该流程被撤回");
                        processCoreService.executeCallBackProcess(ts.get(0).getId(),variables,userId, ts.get(1).getTaskDefinitionKey(), businessEntityVO);
                    }
                }
            }
            return new ResponseBean(CommonResultCode.SUCCESS.getCode(), "撤回流程" + CommonResultCode.SUCCESS.getMsg(), null);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("流程撤回方法：" + e.getMessage());
            return new ResponseBean(CommonResultCode.FAIL.getCode(), "撤回" + CommonResultCode.FAIL.getMsg() + "，请联系管理员！", null);
        }
    }

    /**
     * 结束流程方法
     *
     * @param businessId 业务编码
     * @return
     * @throws
     * @author cg
     * @date 2019-09-06 15:09
     * @since
     */
    @PutMapping("/endProcess")
    @ApiOperation(value = "结束流程方法", notes = "结束流程方法")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "businessId", value = "业务ID（所属业务的ID例如合同的ID）", required = true, dataType = "String"),
            @ApiImplicitParam(name = "businessCode", value = "业务编码（例如合同编码等参照FlowBusinessCode中的Value）", required = true, dataType = "String")
    })
    public ResponseBean endProcess(AuditInfo auditInfo,String businessId, String flowCode, HttpServletRequest request) {
        String userId = this.getUserId(this.getTokenString(request));
        BusinessEntityVO businessEntityVO = new BusinessEntityVO();
        businessEntityVO.setBusinessId(businessId);
        businessEntityVO.setFlowCode(flowCode);
        Map<String, Object> variables = new HashMap<>();
        // 封装实例记录
        InstanceRecord instanceRecord = instanceRecordService.getInstanceRecordByObj(businessId,flowCode);
        try {
            if (instanceRecord != null) {
                // 根据流程实例id获取流程实例
                List<HistoricTaskInstance> ts = historyService.createHistoricTaskInstanceQuery().processInstanceId(instanceRecord.getRunProcessInstanceId()).processUnfinished().orderByTaskCreateTime().desc().list();
                if (ts!=null&&ts.size()>0) {
                    QueryWrapper<NodeConfig> configQueryWrapper = new QueryWrapper<>();
                    configQueryWrapper.lambda().eq(NodeConfig::getFlowCode, flowCode);
                    configQueryWrapper.lambda().eq(NodeConfig::getNodeCode, ts.get(0).getTaskDefinitionKey());
                    List<NodeConfig> list = nodeConfigService.list(configQueryWrapper);
                    if (list != null && list.size() > 0) {
                        //String auditStr
                        variables.put(list.get(0).getFlowCode(), -2);
                        variables.put(FlowApproveOpinion.APPROVE_MESSAGE.getValue(), "该流程已被直接结束");
                        processCoreService.endProcess(ts.get(0).getId(),variables, businessEntityVO);
                    }

                }
            }
            return new ResponseBean(CommonResultCode.SUCCESS.getCode(), "结束流程" + CommonResultCode.SUCCESS.getMsg(), null);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("结束流程方法：" + e.getMessage());
            return new ResponseBean(CommonResultCode.FAIL.getCode(), "结束流程" + CommonResultCode.FAIL.getMsg() + "，请联系管理员！", null);
        }
    }

    /**
     * 转办委托他人的流程方法
     *
     * @param businessId  业务编码
     * @param otherUserId 其他用户ID
     * @return
     * @throws
     * @author cg
     * @date 2019-09-06 15:09
     * @since
     */
    @PutMapping("/transferProcess")
    @ApiOperation(value = "转办委托他人的流程方法", notes = "转办委托他人的流程方法")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "businessId", value = "业务ID（所属业务的ID例如合同的ID）", required = true, dataType = "String"),
            @ApiImplicitParam(name = "flowCode", value = "流程编码", required = true, dataType = "String"),
            @ApiImplicitParam(name = "otherUserId", value = "转到其他人的UserID", required = true, dataType = "String")
    })
    public ResponseBean transferProcess(String businessId, String otherUserId, String flowCode, HttpServletRequest request) {
        String userId = this.getUserId(this.getTokenString(request));
        BusinessEntityVO businessEntityVO = new BusinessEntityVO();
        businessEntityVO.setBusinessId(businessId);
        businessEntityVO.setFlowCode(flowCode);
        // 封装实例记录
        InstanceRecord instanceRecord = instanceRecordService.getInstanceRecordByObj(businessId,flowCode);
        try {
            if (instanceRecord != null) {
                List<Task> tasks = baseFlowService.getInstanceUserTasks(instanceRecord.getRunProcessInstanceId(), userId);
                if (tasks.size() > 0) {
                    taskService.delegateTask(tasks.get(0).getId(), otherUserId);
                }
            }
            return new ResponseBean(CommonResultCode.SUCCESS.getCode(), "结束流程" + CommonResultCode.SUCCESS.getMsg(), null);
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error("结束流程方法：" + e.getMessage());
            return new ResponseBean(CommonResultCode.FAIL.getCode(), "结束流程" + CommonResultCode.FAIL.getMsg() + "，请联系管理员！", null);
        }
    }

    /**
     * 根据实例定义的编码查询图片资源
     *
     * @param businessId 业务编码
     * @return
     * @throws
     * @author cg
     * @date 2019-08-27 11:40
     * @since
     */
    @GetMapping(value = "/getImage")
    @ApiOperation(value = "根据实例定义的编码查询图片资源", notes = "根据实例定义的编码查询图片资源")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "businessId", value = "业务ID（所属业务的ID例如合同的ID）", required = true, dataType = "String"),
            @ApiImplicitParam(name = "flowCode", value = "流程编码", required = true, dataType = "String")
    })
    public void getImage(String businessId,String flowCode, HttpServletResponse response) {
        // 封装实例记录
        InstanceRecord instanceRecord = instanceRecordService.getInstanceRecordByObj(businessId,flowCode);
        ProcessDefinition processDefinition = repositoryService.createProcessDefinitionQuery().processDefinitionId(instanceRecord.getRunDefinitionId()).singleResult();
        String resourceName = processDefinition.getDiagramResourceName();
        InputStream resourceAsStream = repositoryService.getResourceAsStream(processDefinition.getDeploymentId(), resourceName);
        try {
            byte[] b = new byte[1024];
            int len = -1;
            while ((len = resourceAsStream.read(b, 0, 1024)) != -1) {
                response.getOutputStream().write(b, 0, len);
            }
            response.getOutputStream().close();
        } catch (Exception e) {
            e.printStackTrace();
            LOGGER.error(e.getMessage());
        }
        /**if (EncryptUtil.getInstance().SHA1(instanceRecord.getRunDefinitionId()).equals(processDefinitionIdKey)) {
         } else {
         try {
         response.getOutputStream().write(0);
         } catch (Exception e) {
         e.printStackTrace();
         LOGGER.error(e.getMessage());
         }
         }*/
    }

    /**
     * 查看流程图的当前活动节点
     *
     * @param businessId 定义实例ID
     * @return
     * @throws
     * @author cg
     * @date 2019-09-06 16:07
     * @since
     */
    @GetMapping(value = "/getCurrentView")
    @ApiOperation(value = "查看流程图的当前活动节点", notes = "查看流程图的当前活动节点")
    @ApiImplicitParam(name = "businessId", value = "业务ID（所属业务的ID例如合同的ID）", required = true, dataType = "String")
    public ResponseBean getCurrentView(String businessId,String flowCode) {
        // 封装实例记录
        InstanceRecord instanceRecord = instanceRecordService.getInstanceRecordByObj(businessId,flowCode);
        ProcessDefinitionEntity pdm = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(instanceRecord.getRunDefinitionId());
        ProcessInstance pi = runtimeService.createProcessInstanceQuery().processInstanceId(instanceRecord.getRunDefinitionId()).singleResult();
        ActivityImpl ai = pdm.findActivity(pi.getActivityId());
        List<Integer> list = new ArrayList<>();
        list.add(ai.getX());
        list.add(ai.getY());
        list.add(ai.getWidth());
        list.add(ai.getHeight());
        return new ResponseBean(CommonResultCode.SUCCESS.getCode(), "结束流程" + CommonResultCode.SUCCESS.getMsg(), list);
    }

    /**
     * 根据业务id,流程code查找审批记录
     *
     * @param businessId   业务id
     * @param flowCode 业务流程code
     * @return ResponseBean 返回结果
     * @author xuwenwu
     * @date 2019-11-11 16:43
     * @since 4.0
     */
    @GetMapping(value = "/getActivitiRecordView")
    @ApiOperation(value = "根据业务id,业务code查看审批日志", notes = "根据业务id,业务code查看审批日志")
    @ApiImplicitParams({
            @ApiImplicitParam(name = "businessId", value = "业务ID（所属业务的ID例如合同的ID）", required = true, dataType = "Long"),
            @ApiImplicitParam(name = "businessCode", value = "业务编码（例如合同编码等参照FlowBusinessCode中的Value）", required = true, dataType = "String"),
    })
    public ResponseBean getActivitiRecordView(@RequestParam Long businessId, @RequestParam String flowCode) {
        try {
            List<NodeRecord> list = nodeRecordService.selectNodeRecordByBusinessIdAndFlowCodeList(businessId, flowCode);
            return new ResponseBean(CommonResultCode.SUCCESS.getCode(), CommonResultCode.SUCCESS.getMsg(), list);
        } catch (Exception e) {
            e.printStackTrace();
            return new ResponseBean(CommonResultCode.FAIL.getCode(), "查询业务审批日志失败", null);
        }
    }
}
